/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ihmprojet.view.onglets;

import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.TreeLayout;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.picking.PickedState;
import ihmprojet.core.Context;
import ihmprojet.core.Events.SelectionChangedEvent;
import ihmprojet.core.model.Arrete;
import ihmprojet.core.model.Sommet;
import ihmprojet.core.model.operateur.OperateurBinaire;
import ihmprojet.core.model.operateur.OperateurUnaire;
import ihmprojet.view.FenetrePrincipale;
import ihmprojet.view.onglets.exception.ExceptionPasDeSommetSelectionner;
import ihmprojet.view.renderer.EdgeLabelTransformer;
import ihmprojet.view.renderer.TreeOperatorRenderer;
import ihmprojet.view.transformer.IconLoader;
import ihmprojet.view.transformer.SommetIconTransformer;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.Iterator;

/**
 * @todo faire les operation binaire
 * @author morgan & thomas
 */
public class FenetreContexte extends javax.swing.JPanel implements OngletInterface {

    private static final int DEFAULT_HEIGHT = 70;
    private static final int DEFAULT_WIDTH = 100;
    private Context context;
    private String id;
    private VisualizationViewer<Sommet, Arrete> vv;
    private FenetrePrincipale fenp = null;
    private ScalingControl scaler = new CrossoverScalingControl();// pour le zoom
    private Dimension dim;
    private int distx = DEFAULT_WIDTH;
    private int disty = DEFAULT_HEIGHT;

    /**
     * Creates new form FenetreContexte
     */
    public FenetreContexte(Context c, String id, FenetrePrincipale fp, Dimension d) {
        initComponents();
        this.context = c;
        this.id = id;
        this.setName(id);
        this.setLayout(new FlowLayout());
        this.setBackground(new Color(55, 55, 55));
        fenp = fp;
        dim = d;
        renderTree();
    }

    public void increaseHigh() {
        disty += 5;
        fireChangement();
    }

    public void decreaseHigh() {
        disty -= 5;
        fireChangement();
    }

    public void restoreDefalutHighWith() {

        distx = DEFAULT_WIDTH;
        disty = DEFAULT_HEIGHT;
                fireChangement();
    }

    public void increaseWidth() {
        distx += 5;
        fireChangement();
    }

    public void decreaseWidth() {
        distx -= 5;
        fireChangement();
    }

    private Layout<Sommet, Arrete> createLayout() {
        Layout<Sommet, Arrete> layout = new TreeLayout<>(context.getTree(), distx, disty);
        return layout;
    }

    private void renderTree() {
        IconLoader il = new IconLoader();
        il.load(new File("images/tasks"), "gif");

        vv = new VisualizationViewer<>(this.createLayout());

        vv.setRenderer(new TreeOperatorRenderer<Sommet, Arrete>());
        DefaultModalGraphMouse dmgm = new DefaultModalGraphMouse();
        dmgm.setMode(ModalGraphMouse.Mode.PICKING);
        vv.setGraphMouse(dmgm);
        vv.getRenderContext().setVertexIconTransformer(new SommetIconTransformer(il));
        vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
        vv.getRenderContext().setEdgeLabelTransformer(new EdgeLabelTransformer());
        this.add(new GraphZoomScrollPane(vv));
        vv.setPreferredSize(dim);

// Notification de changement de sélection
        final PickedState<Sommet> pickedState = vv.getPickedVertexState();

        // Attach the listener that will print when the vertices selection changes.
        pickedState.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                Object subject = e.getItem();
                // The graph uses Integers for vertices.
                if (subject instanceof Sommet) {
                    Sommet vertex = (Sommet) subject;
                    if (pickedState.isPicked(vertex)) {
                        fenp.fireChangementSelection(new SelectionChangedEvent());
                    } else {
                        fenp.fireChangementSelection(new SelectionChangedEvent(false));
                    }
                }
            }
        });
    }

    /**
     * @throws ExceptionPasDeSommetSelectionner
     * @return le sommet
     */
    public Sommet getSelectedVertex() throws ExceptionPasDeSommetSelectionner {
        // Je sais pas comment faire s'il y a plusieurs sommet selectionné donc je prend le dernier du set ...
        Iterator it = vv.getPickedVertexState().getPicked().iterator();
        Sommet s = null;

        while (it.hasNext()) {
            s = (Sommet) it.next();
        }
        if (s == null) {
            throw new ExceptionPasDeSommetSelectionner(this.fenp);
        }
        return s;
    }

    public void addOperateurUnaire(Sommet s, OperateurUnaire.TypeUnaire type) {
        context.ajouterOperateurUnaire(s, new OperateurUnaire(type));
        fireChangement();
    }

    public void supprimerOperateurUnaire(Sommet s, OperateurUnaire.TypeUnaire type) {
        context.supprimerOperateurUnaire(s, new OperateurUnaire(type));
        fireChangement();
    }

    public void addOperateurBinaire(Sommet s1, Sommet s2, String nomOp) {

        this.context.ajouterOperateurBinaire(s1, s2, new OperateurBinaire(nomOp));
        fireChangement();
    }

    public void addVertex(String name, Sommet.Type type) {
        Sommet v;
        try {
            v = getSelectedVertex();
            context.ajouterSommet(v, name, type);
        } catch (ExceptionPasDeSommetSelectionner e) {// si pas de sommet présent
            v = null;
        }
        this.fireChangement();
    }

    public void zoomIn() {
        setZoom(1);
    }

    public void zoomOut() {
        setZoom(-1);
    }

    private void setZoom(int amount) {
        scaler.scale(vv, amount > 0 ? 1.1f : 1 / 1.1f, vv.getCenter());
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setBackground(new java.awt.Color(51, 51, 51));
        setOpaque(false);
        setPreferredSize(new java.awt.Dimension(800, 800));
        addComponentListener(new java.awt.event.ComponentAdapter() {
            public void componentResized(java.awt.event.ComponentEvent evt) {
                formComponentResized(evt);
            }
        });
        addHierarchyBoundsListener(new java.awt.event.HierarchyBoundsListener() {
            public void ancestorMoved(java.awt.event.HierarchyEvent evt) {
            }
            public void ancestorResized(java.awt.event.HierarchyEvent evt) {
                formAncestorResized(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 800, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 800, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    private void formComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentResized
    }//GEN-LAST:event_formComponentResized

    private void formAncestorResized(java.awt.event.HierarchyEvent evt) {//GEN-FIRST:event_formAncestorResized
        Dimension d = new Dimension(fenp.getSizePanContext().getSize().width - 20, fenp.getSizePanContext().getSize().height - 20);
        vv.setPreferredSize(d);
    }//GEN-LAST:event_formAncestorResized

    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
    public void fireChangement() {
        vv.setGraphLayout(createLayout());
        repaint();
        fenp.fireChangementFenContexte();
    }

    @Override
    public String getId() {
        return id;
    }
}
